using System;
using System.Collections.Generic;
using UnityEngine;
using XLua;
using Yoozoo.Gameplay;
using Yoozoo.Gameplay.RTS;
using Yoozoo.Managers;
using Yoozoo.Managers.ResourceManagerV2.Runtime;

namespace com.youzu.got.protocol
{
    /// <summary>
    /// 小兵攻击，区域的圈圈 区域技能 等的管理器
    /// </summary>
    public class RTSBattleEffectManager
    {
        private struct BattleEffectData
        {
            public int id;
            public GameObject effect;
            public int resourceId;
            public float startTime;
            public float endTime;
            public List<bool> isActive;
        }

        public enum ESoldierEffectType
        {
            DeadBlood = 1,
            KillBlood = 2,
            SoldierHit = 3,
            SoldierAttack = 4,
        }


        public struct EffectConfig
        {
            public int id;
            public int sub_id;
            public string resource_path;
            public int resource_id;
            public int effect_start_time;
            public int last_time;
            public int effect_direction;
            public int move_speed;
            public int bind_target;
            public Vector3[] offset;
            public int bind_type;
            public Vector3 rotation;
            public float scale;

        }
        
        private List<BattleEffectData> m_effectList = new List<BattleEffectData>();
        private List<BattleEffectData> m_directorList = new List<BattleEffectData>();
        private List<BattleEffectData> m_testList = new List<BattleEffectData>();
        private Dictionary<int,EffectController> m_ecDic = new Dictionary<int,EffectController>();
        public static RTSBattleEffectManager Instance;
        private static readonly int Color = Shader.PropertyToID("_TintColor");
        private Dictionary<int,Dictionary<int,EffectConfig>> effectConfigs = new Dictionary<int,Dictionary<int,EffectConfig>>();
        private int ecIndex = 0;
        private EffectConfig defaultConfig;
        private BattleEffectPool battleEffectPool;
        
        static List<MeshRenderer> meshRenders = new List<MeshRenderer>();
        private ResLoader _resLoader;
        public void Init()
        {
            Instance = this;
            _resLoader = ResLoader.Alloc();
            battleEffectPool = new BattleEffectPool();
            battleEffectPool.Init();
        }
        
        
        public static void ShowSkillDirectorByType(int team,int type, Vector3 forward,Dictionary<string,float> director_parmData,
            Vector3 selfPosition, Vector3 targetPosition,
            float endTime = 1, bool area = false)
        {
            var _ct = TimeUtils.GetClientTickTime();
            BattleEffectData data = new BattleEffectData();
            GameObject director = null;
            int resourceId = 0;
            Vector3 scale = Vector3.zero;
            Vector3 position = Vector3.zero;
            switch (type)
            {
                case 1: //目标
                    break;
                //普通技能
                case 2: //以目标为中心的圆范围
                    resourceId = 709;
                    float radius = BattleUtils.GetValueStrFloat(director_parmData, "radius");
                    scale = new Vector3(0.16f, 0.16f, 0.16f) * radius;
                    position = selfPosition + new Vector3(0, 0.02f, 0);
                    break;
                case 3: //以目标为方向的扇形范围
                    float a = BattleUtils.GetValueStrFloat(director_parmData, "angle");
                    float localScale = 0.15f;
                    if (a == 120 || a == 90)
                    {
                        resourceId = 710;
                    }
                    else if (a == 180)
                    {
                        resourceId = 711;
                        localScale = 0.18f;
                    }

                    float r = BattleUtils.GetValueStrFloat(director_parmData, "radius");
                    position = selfPosition + new Vector3(0, 0.02f, 0);
                    scale = new Vector3(localScale, localScale, localScale) * r;
                    break;
                case 4: //以目标为方向的矩形范围
                    resourceId = 712;
                    float width = BattleUtils.GetValueStrFloat(director_parmData, "width");
                    float height = BattleUtils.GetValueStrFloat(director_parmData, "length");
                    position = selfPosition + new Vector3(0, 0.02f, 0);
                    scale = new Vector3(0.16f * width, 1, 0.085f * height);
                    break;
            }

            director = ArmyManager.GetResourceById(resourceId);
            if (director != null)
            {
                if (forward != Vector3.zero)
                {
                    director.transform.position = Vector3.zero;
                    director.transform.forward = forward;
                    director.transform.localEulerAngles = new Vector3(0,director.transform.localEulerAngles.y,0);
                    //var rot = Quaternion.FromToRotation(director.transform.forward, forward);
                    //director.transform.rotation = rot;
                }
                director.transform.position = position;
                director.transform.localScale = scale;
                data.effect = director;
                data.startTime = _ct;
                data.endTime = _ct + endTime;
                data.resourceId = resourceId;
                UnityEngine.Color color = new UnityEngine.Color32(0, 255, 0,255);

                var ani = director.transform.GetComponentInChildren<Animation>();
                

                if (team == 0)
                {
                    color = new Color32(0, 255, 26,50);
                }
                else
                {
                    color = new Color32(255, 0, 0,255);
                }
                if (ani!=null)
                {
                    string animName = string.Empty;
                    foreach (AnimationState item in ani)
                    {
                        if (!item.name.Contains("red") && team == 0)
                        {
                            animName = item.name;
                        }

                        if (item.name.Contains("red") && team != 0)
                        {
                            animName = item.name;
                        }
                    }
                    ani.Play(animName);
                }
                director.transform.GetComponentsInChildren<MeshRenderer>(meshRenders);
                for (int i = 0; i < meshRenders.Count; i++)
                {
                    for (int j = 0; j < meshRenders[i].materials.Length; j++)
                    {
                        var mat = meshRenders[i].materials[j];
                        mat.SetColor(Color,color);
                    }
                }
                Instance.m_directorList.Add(data);

                
                /*if (area)//区域特效需要再显示一个，慢慢放大
                {
                    var newGameObject = GameObject.Instantiate(director, null, true);
                    newGameObject.transform.position = position;
                    newGameObject.transform.forward = director.transform.forward;
                    newGameObject.transform.localScale = Vector3.zero;
                    newGameObject.name = "newArea";
                    TweenUtils.TweenFloat(0, 1, endTime,
                        (percent) =>
                        {
                            newGameObject.transform.localScale = percent * scale;
                        },
                        ()=>
                        {
                            GameObject.Destroy(newGameObject);
                        });
                }*/
            }
        }
        
        public int PlayEffect(int effectId, Vector3 selfPosition,Vector3 targetPosition,int team,bool needChangeEffectColor = false)
        {
            var effect = ClassManager.Get<EffectController>();
            effect.Play(effectId,selfPosition,targetPosition,team,needChangeEffectColor);
            ecIndex++;
            int id = ecIndex;
            m_ecDic.Add(ecIndex,effect);

            return id;
        }

        public int PlayAreaEffect(int effectId, Vector3 selfPosition, Vector3 targetPosition, float duration)
        {
            var effect = ClassManager.Get<EffectController>();
            effect.PlayArea(effectId,selfPosition,targetPosition,duration);
            ecIndex++;
            int id = ecIndex;
            m_ecDic.Add(ecIndex,effect);
            return id;
        }

        public int PlayBuffEffect(int effectId, Transform parent)
        {
            var effect = ClassManager.Get<EffectController>();
            effect.PlayBuffEffect(effectId,parent);
            ecIndex++;
            int id = ecIndex;
            m_ecDic.Add(ecIndex,effect);
            return id;
        }

        public void RemoveEffect(int effectId)
        {
            if (m_ecDic.TryGetValue(effectId, out var effectController))
            {
                m_ecDic.Remove(effectId);
                ClassManager.Free(effectController);
            }
        }

        public void Update()
        {
            var _ct = TimeUtils.GetClientTickTime();
            for (int i = m_effectList.Count - 1; i >= 0; i--)
            {
                if (_ct > m_effectList[i].endTime)
                {
                    ArmyManager.RecoverResourceById(m_effectList[i].resourceId,m_effectList[i].effect);
                    m_effectList.RemoveAt(i);
                }
                else if (_ct > m_effectList[i].startTime && !m_effectList[i].isActive[m_effectList[i].isActive.Count - 1])
                {
                    var animator = m_effectList[i].effect.GetComponent<EffectAnimatorData>();
                    if (animator == null)
                    {
                        m_effectList[i].effect.SetActive(true);
                    }
                    else
                    {
                        animator.SetActive(true);
                    }
                    m_effectList[i].isActive.Add(true);
                }
            }

            for (int i = m_directorList.Count - 1; i >= 0; i--)
            {
                if (_ct > m_directorList[i].endTime)
                {
                    ArmyManager.RecoverResourceById(m_directorList[i].resourceId,m_directorList[i].effect);
                    m_directorList.RemoveAt(i);
                }
            }
            

            foreach (var item in m_ecDic.Values)
            {
                item.Update();
            }

            battleEffectPool.Update();
        }

        private Vector3 GetVector3ByLuaTable(LuaTable table)
        {
            float x = 0;
            float y = 0;
            float z = 0;
            for (int i = 1; i <= table.Length; i++)
            {
                var value = table.Get<int, double>(i);
                if (i == 1)
                {
                    x = (float) value;
                }
                else if (x == 2)
                {
                    y = (float) value;
                }
                else if (x == 3)
                {
                    z = (float) value;
                }
            }
            return new Vector3(x,y,z);
        }

        public void LoadEffect(string path, Action<GameObject> onLoadOver)
        {
            _resLoader.Add2Load("Assets/ResourcesAssets/Prefabs/Effect/Battle/" + path + ".prefab", (success,name,asset) =>
            {
                if (success)
                {
                    onLoadOver(GameObject.Instantiate(asset as GameObject));
                }
            }).Load();
        }

        public void GetEffect(string path, Action<GameObject> onOver)
        {
            battleEffectPool.GetEffect(path, onOver);
        }

        public void RecoverEffect(string path, GameObject effect)
        {
            battleEffectPool.RecoverEffect(path,effect);
        }

        private double getDouble(LuaTable table,string key)
        {
            return table.ContainsKey(key)?table.Get<string,double>(key):0;
        }

        public void PreloadEffectConfig(LuaTable table)
        {
            for (int i = 1; i <= table.Length; i++)
            {
                var config = table.Get<int, LuaTable>(i);
                if (config != null)
                {
                    double id = getDouble(config,"id");
                    double sub_id = getDouble(config,"sub_id");
                    double resource_id = getDouble(config,"resource_id");
                    double effect_start_time =getDouble(config,"effect_start_time");
                    double last_time = getDouble(config,"last_time");
                    double effect_direction = getDouble(config,"effect_direction");
                    double move_speed = getDouble( config,"move_speed");
                    double bind_target = getDouble(config,"bind_target");
                    LuaTable offsetTable = config.Get<string, LuaTable>("offset");
                    Vector3[] offset = new Vector3[offsetTable.Length];
                    for (int j = 1; j <= offsetTable.Length; j++)
                    {
                        offset[j - 1] = new Vector3();
                        var vector3s = offsetTable.Get<int, LuaTable>(j);
                        for (int k = 1; k <= vector3s.Length; k++)
                        {
                            if (k == 1)
                            {
                                offset[j - 1].x = vector3s.Get<int, float>(k);
                            }
                            if (k == 2)
                            {
                                offset[j - 1].y = vector3s.Get<int, float>(k);
                            }
                            if (k == 3)
                            {
                                offset[j - 1].z = vector3s.Get<int, float>(k);
                            }
                        }
                    }
                    double bind_type = getDouble( config,"bind_type");
                    Vector3 rotation =  config.Get<string, Vector3>("rotation");
                    double scale = getDouble(config,"scale");
                    int configId = (int) id;
                    int configSubId = (int) sub_id;
                    string path = (string) config["resource_path"];
                    if (!effectConfigs.ContainsKey(configId))
                    {
                        var dic = new Dictionary<int, EffectConfig>();
                        effectConfigs.Add(configId,dic);
                    }
                    effectConfigs[configId].Add(configSubId,new EffectConfig
                    {
                        id = configId,
                        sub_id = configSubId,
                        resource_id = (int)resource_id,
                        effect_start_time = (int)effect_start_time,
                        last_time = (int)last_time,
                        effect_direction = (int)effect_direction,
                        move_speed = (int)move_speed,
                        bind_target = (int)bind_target,
                        offset = offset,
                        bind_type = (int)bind_type,
                        rotation = rotation,
                        scale = (float)scale,
                        resource_path = path,
                    });
                }
            }
        }

        public EffectConfig GetEffectConfig(int id,int subId)
        {
            if (effectConfigs.TryGetValue(id, out var configs))
            {
                if (configs.TryGetValue(id, out var config))
                {
                    return config;
                }
            }

            return defaultConfig;
        }

        public Dictionary<int, EffectConfig> GetEffectConfigs(int id)
        {
            if (effectConfigs.TryGetValue(id, out var configs))
            {
                return configs;
            }

            return null;
        }
        
        public void Dispose()
        {
            for (int i = m_effectList.Count - 1; i >= 0; i--)
            {
                ArmyManager.RecoverResourceById(m_effectList[i].resourceId,m_effectList[i].effect);
            }
            m_effectList.Clear();
            for (int i = m_directorList.Count - 1; i >= 0; i--)
            {
                ArmyManager.RecoverResourceById(m_directorList[i].resourceId,m_directorList[i].effect);
            }
            m_directorList.Clear();

            battleEffectPool.Dispose();

            if (_resLoader != null)
            {
                _resLoader.Recycle2Cache();
                _resLoader = null;
            }
        }
    }
}
